/*
* Copyright (C) 2020 ~ 2024 chaigec All Rights Reserved.
*
* Author:     chaigec <chaigec@163.com>
* Maintainer: chaigec <chaigec@163.com>

 * Use of this source code is governed by MIT license that can be found in the
 * LICENSE file in the root of the source tree. All contributing project authors
 * may be found in the AUTHORS file in the root of the source tree.
*/

#include "MkSip/MkSipServer.h"
#include "MkSipUdpListener.h"
#include "MkSipTcpListener.h"
#include "MkSipMessage.h"
#include "MkEvent/MkEventPool.h"
#include "MkSipUtil.h"
#include "MkEvent/MkTimer.h"
#include "MkUtil/MkUtil.h"
#include "MkUtil/MkLog.h"

CMkSipServer::CMkSipServer(CMkEventPool* pEventPool, CMkTimer* pTimer)
    : m_pEventPool(pEventPool)
    , m_pTimer(pTimer)
    , m_SipSeqNo(1)
    , m_pTcpListener(nullptr)
    , m_pUdpListener(nullptr)
{

}

Uint32 CMkSipServer::Start(const MkString& SipId, const MkString& Realm, const MkString& UdpListenHost, Uint16 UdpListenPort, const MkString& UdpPublicHost, Uint16 UdpPublicPort, const MkString& TcpListenHost, Uint16 TcpListenPort, const MkString& TcpPublicHost, Uint16 TcpPublicPort)
{
    Uint32 ErrorCode = NoneError;
    if (UdpListenPort) {
        m_pUdpListener = new CMkSipUdpListener(m_pEventPool->GetFreeEvent(), m_pTimer, this);
        if (nullptr != m_pUdpListener) {
            ErrorCode = m_pUdpListener->Start(UdpListenHost, UdpListenPort, UdpPublicHost, UdpPublicPort);
            if (NoneError != ErrorCode) {
                MkErrorLog("start udp sip server(%s:%d) failed\n", UdpPublicHost.c_str(), UdpListenPort);
                MkDelete(m_pUdpListener);
            }
        }
    }
    if (TcpListenPort) {
        m_pTcpListener = new CMkSipTcpListener(m_pEventPool, m_pTimer, this);
        if (nullptr != m_pTcpListener) {
            ErrorCode = m_pTcpListener->Start(TcpListenHost, TcpListenPort, TcpPublicHost, TcpPublicPort);
            if (NoneError != ErrorCode) {
                MkErrorLog("start udp sip server(%s:%d) failed\n", TcpListenHost.c_str(), TcpListenPort);
                MkDelete(m_pTcpListener);
            }
        }
    }

    if (!m_pTcpListener
        && !m_pUdpListener) {
        return SocketListenFailed;
    }
    MkInfoLog("start sip udp:%d tcp:%d success\n", UdpListenPort, TcpListenPort);
    m_SipId = SipId;
    m_Realm = Realm;
    return m_pTimer->AddTimer([this]() {
        OnTransactionTimer();
    }, CMkSipUtil::GetInstance().GetTransactionCheckSec() * 1000, m_TranactionCheckTimer);
}

Uint32 CMkSipServer::Stop()
{
    m_pTimer->DeleteTimer(m_TranactionCheckTimer);
    m_TranactionLock.WLock();
    m_MapTranaction.clear();
    m_TranactionLock.WUnlock();
    m_DialogLock.WLock();
    m_MapDialog.clear();
    m_DialogLock.WUnlock();
    MkDelete(m_pTcpListener);
    MkDelete(m_pUdpListener);
    return NoneError;
}

void CMkSipServer::SetUdpPublicHost(const MkString& PublicHost)
{
    if (m_pUdpListener) {
        m_pUdpListener->SetPublicHost(PublicHost);
    }
}

void CMkSipServer::SetUdpPublicPort(const Uint16& PublicPort)
{
    if (m_pUdpListener) {
        m_pUdpListener->SetPublicPort(PublicPort);
    }
}

void CMkSipServer::SetTcpPublicHost(const MkString& PublicHost)
{
    if (m_pTcpListener) {
        m_pTcpListener->SetPublicHost(PublicHost);
    }
}

void CMkSipServer::SetTcpPublicPort(const Uint16& PublicPort)
{
    if (m_pTcpListener) {
        m_pTcpListener->SetPublicPort(PublicPort);
    }
}

const MkString& CMkSipServer::GetUdpPublicHost() const
{
    if (m_pUdpListener) {
        return  m_pUdpListener->GetPublicHost();
    }
    return CMkUtil::GetEmptyString();
}

const MkString& CMkSipServer::GetTcpPublicHost() const
{
    if (m_pTcpListener) {
        return  m_pTcpListener->GetPublicHost();
    }
    return CMkUtil::GetEmptyString();
}

Uint32 CMkSipServer::StopCall(const MkString& CallId, const SipMsgCompleteCallback& Cb)
{
    return SendDialogMessage(CallId, MkSipMethodBye, Cb);
}

Uint32 CMkSipServer::StopSubscribe(const MkString& SubscribeId, const MkMapString& ExtendHeaders, const SipMsgCompleteCallback& Cb)
{
    return SendDialogMessage(SubscribeId, MkSipMethodSubscribe, Cb, MkSipContentNone, ExtendHeaders);
}

Uint32 CMkSipServer::Register(const MkString& RegisterId, const MkMapString& ExternHeader, const SipMsgCompleteCallback& Cb)
{
    CMkSipDialog Dialog;
    Uint32 ErrorCode = GetDialog(RegisterId, Dialog);
    MkCheckErrorLog(ErrorCode, "input invalid dialog id:%s\n", RegisterId.c_str());

    CMkSipMessage SipMessage = Dialog.GetRequest();
    SipMessage.SetSipUri(Dialog.GetRequest().GetUri());
    SipMessage.SetTo(Dialog.GetResponse().GetTo());
    SipMessage.SetCSeq(m_SipSeqNo++);
    SipMessage.ClearOtherHeaders();
    SipMessage.AddOtherHeaders(ExternHeader);
    SipMessage.ClearVia();

    return SendSipMessage(SipMessage, [this, Cb](const CMkSipMessage& SipMessage) {
        AddSipMessageToTransaction(SipMessage);
        if (Cb) {
            Cb(SipMessage);
        }
    });
}

Uint32 CMkSipServer::SubscribeNotify(const MkString& SubscribeId, const MkString& strEvent, const MkString& State, const MkMapString& StateExpend, const MkSipContentType& ContentType, const MkString& ContentBody, const SipMsgCompleteCallback& Cb)
{
    MkMapString OtherHeaders;
    OtherHeaders["Event"] = strEvent;

    MkString strState = State;
    MkMapString::const_iterator it = StateExpend.begin();
    for (; it != StateExpend.end(); it++) {
        strState += ";" + it->first + "=" + it->second;
    }
    OtherHeaders["Subscription-State"] = strState;
    return SendDialogMessage(SubscribeId, MkSipMethodNotify, Cb, ContentType, OtherHeaders, ContentBody);
}

Uint32 CMkSipServer::CallInfo(const MkString& CallId, const MkSipContentType& ContentType, const MkString& ContentBody, const SipMsgCompleteCallback& Cb)
{
    return SendDialogMessage(CallId, MkSipMethodInfo, Cb, ContentType, MkMapString(), ContentBody);
}

Uint32 CMkSipServer::CallMessage(const MkString& CallId, const MkSipContentType& ContentType, const MkString& ContentBody, const SipMsgCompleteCallback& Cb)
{
    return SendDialogMessage(CallId, MkSipMethodMessage, Cb, ContentType, MkMapString(), ContentBody);
}

Uint32 CMkSipServer::SendSipRequest(const MkString& SipId, const MkString& DstId, const MkString& SipRealm, const MkSipMethod& Method, const MkString& RemoteHost, Uint16 RemotePort, BOOL bTcp, const SipMsgCompleteCallback& Cb, const MkMapString& OtherHeader/* = MkMapString()*/, const MkSipContentType& ContentType/* = MkSipContentNone*/, const MkString& ContentBody/* = ""*/, const MkString& DiscribeName/* = ""*/)
{
    CMkSipMessage SipRequest;
    CMkSipUri RemoteUri;
    CMkSipFrom From;
    CMkSipFrom To;

    CMkSipUri FromUri;
    CMkSipUri ToUri;
    BOOL bNat = !CMkUtil::IsLanIp(RemoteHost);

    //only dailoag message type has contact header
    if (MkSipMethodRegister == Method
        || MkSipMethodInvite == Method
        || MkSipMethodSubscribe == Method) {
        CMkSipContact Contact;
        CMkSipUri ContactUri;
        if (bTcp) {
            if (bNat) {
                ContactUri.SetHost(m_pTcpListener->GetPublicHost());
                ContactUri.SetPort(m_pTcpListener->GetPublicPort());
            } else {
                ContactUri.SetHost(m_pTcpListener->GetListenHost());
                ContactUri.SetPort(m_pTcpListener->GetListenPort());
            }
        } else {
            if (bNat) {
                ContactUri.SetHost(m_pUdpListener->GetPublicHost());
                ContactUri.SetPort(m_pUdpListener->GetPublicPort());
            } else {
                ContactUri.SetHost(m_pUdpListener->GetListenHost());
                ContactUri.SetPort(m_pUdpListener->GetListenPort());
            }
        }
        ContactUri.SetUserName(m_SipId);
        Contact.SetUri(ContactUri);
        SipRequest.AddContact(Contact);
    }

    RemoteUri.SetUserName(DstId);
    ToUri.SetUserName(MkSipMethodRegister == Method ? DstId : SipId);
    if (SipRealm.empty()) {
        RemoteUri.SetHost(RemoteHost);
        RemoteUri.SetPort(RemotePort);
        ToUri.SetHost(RemoteHost);
        ToUri.SetPort(RemotePort);
    } else {
        RemoteUri.SetHost(SipRealm);
        ToUri.SetHost(SipRealm);
    }

    FromUri.SetUserName(m_SipId);
    FromUri.SetHost(m_Realm);

    MkString SipCallId;
    CMkUtil::CreateRandomString(Len16, SipCallId);

    From.SetUri(FromUri);
    MkString FromTag;
    CMkUtil::CreateRandomString(Len16, FromTag);
    From.SetDesplayName(DiscribeName);
    From.UpdateParam("tag", FromTag);

    if (MkSipMethodRegister == Method) {
        To.SetUri(FromUri);
    } else {
        To.SetUri(ToUri);
    }



    SipRequest.SetMethod(Method);
    SipRequest.SetSipUri(RemoteUri);
    SipRequest.SetCSeq(m_SipSeqNo++);
    SipRequest.SetFrom(From);
    SipRequest.SetTo(To);
    SipRequest.SetCallId(SipCallId);
    SipRequest.SetContentType(ContentType);
    SipRequest.SetContentBody(ContentBody);
    SipRequest.AddOtherHeaders(OtherHeader);
    SipRequest.SetTcpFlag(bTcp);
    SipRequest.SetRemoteHost(RemoteHost);
    SipRequest.SetRemotePort(RemotePort);

    return SendSipMessage(SipRequest, [this, Cb](const CMkSipMessage& SipMessage) {
        AddSipMessageToTransaction(SipMessage);
        if (Cb) {
            Cb(SipMessage);
        }
    });
}

Uint32 CMkSipServer::SendDialogMessage(const MkString& DialogId, const MkSipMethod& Method, const SipMsgCompleteCallback& Cb, const MkSipContentType& ContentType/* = MkSipContentNone*/, const MkMapString& OtherHeader/* = MkMapString()*/, const MkString& ContentBody/* = ""*/)
{
    CMkSipDialog Dialog;
    Uint32 ErrorCode = GetDialog(DialogId, Dialog);
    MkCheckErrorLog(ErrorCode, "input invalid dialog id:%s\n", DialogId.c_str());

    MkString ContactHost;
    Uint16 ContactPort = 0;
    CMkSipMessage SipMessage;
    SipMessage.SetRequestFlag(TRUE);
    SipMessage.SetCallId(Dialog.GetResponse().GetCallId());
    SipMessage.SetMethod(Method);
    SipMessage.SetTcpFlag(Dialog.GetRequest().IsTcp());
    SipMessage.SetContactHost(Dialog.GetContactHost());
    SipMessage.SetContactPort(Dialog.GetContactPort());
    if (MkSipMethodAck == Method) {
        SipMessage.SetCSeq(Dialog.GetRequest().GetCSeq());
    } else {
        SipMessage.SetCSeq(m_SipSeqNo++);
    }

    //this call to other
    if (CMkSipDialog::MkSipDialogCaller == Dialog.GetCallType()) {
        SipMessage.SetSipUri(Dialog.GetRequest().GetUri());
        SipMessage.SetTo(Dialog.GetResponse().GetTo());
        SipMessage.SetFrom(Dialog.GetResponse().GetFrom());
        SipMessage.SetRemoteHost(Dialog.GetRequest().GetRemoteHost());
        SipMessage.SetRemotePort(Dialog.GetRequest().GetRemotePort());
        if (Dialog.GetResponse().GetVecContact().empty()) {
            ContactHost = Dialog.GetRequest().GetRemoteHost();
            ContactPort = Dialog.GetRequest().GetRemotePort();
        } else {
            ContactHost = Dialog.GetResponse().GetVecContact().begin()->GetUri().GetHost();
            ContactPort = Dialog.GetResponse().GetVecContact().begin()->GetUri().GetPort();
        }
    } else {
        SipMessage.SetSipUri(Dialog.GetRequest().GetFrom().GetUri());
        SipMessage.SetTo(Dialog.GetResponse().GetFrom());
        SipMessage.SetFrom(Dialog.GetResponse().GetTo());
        SipMessage.SetRemoteHost(Dialog.GetResponse().GetRemoteHost());
        SipMessage.SetRemotePort(Dialog.GetResponse().GetRemotePort());
        if (Dialog.GetRequest().GetVecContact().empty()) {
            ContactHost = Dialog.GetResponse().GetRemoteHost();
            ContactPort = Dialog.GetResponse().GetRemotePort();
        } else {
            ContactHost = Dialog.GetRequest().GetVecContact().begin()->GetUri().GetHost();
            ContactPort = Dialog.GetRequest().GetVecContact().begin()->GetUri().GetPort();
        }
    }

    MkMapString::const_iterator it = OtherHeader.begin();
    for (; it != OtherHeader.end(); it++) {
        SipMessage.AddHeader(it->first, it->second);
    }
    SipMessage.AddOtherHeaders(OtherHeader);
    if (MkSipMethodSubscribe == Method) {
        SipMessage.SetContentBody(Dialog.GetRequest().GetBody());
    } else {
        SipMessage.SetContentBody(ContentBody);
    }

    SipMessage.SetContentType(ContentType);
    if (MkSipMethodBye == Method) {
        DeleteDialog(DialogId);
    } else if (MkSipMethodSubscribe == Method) {
        it = SipMessage.GetOtherHeaders().find("Expires");
        if (it != SipMessage.GetOtherHeaders().end() && 0 == std::stoi(it->second)) {
            DeleteDialog(DialogId);
            m_pTimer->DeleteDelayer(DialogId);
        }
    }

    return SendSipMessage(SipMessage, [this, Cb](const CMkSipMessage& SipMessage) {
        AddSipMessageToTransaction(SipMessage);
        if (Cb) {
            Cb(SipMessage);
        }
    });
}

Uint32 CMkSipServer::SendAck(const CMkSipMessage& SipRequest, const CMkSipMessage& SipResponse, const MkMapString& ExtenHeader, const MkString& ContentBody, CMkSipMessage& SipAck)
{
    SipAck.SetVecVia(SipResponse.GetVecVia());
    SipAck.SetRequestFlag(TRUE);
    SipAck.SetTo(SipResponse.GetTo());
    SipAck.SetFrom(SipResponse.GetFrom());
    SipAck.SetSipUri(SipRequest.GetUri());
    SipAck.SetCallId(SipResponse.GetCallId());
    SipAck.SetMethod(MkSipMethodAck);
    SipAck.SetCSeq(SipRequest.GetCSeq().first);

    if (!SipResponse.GetVecContact().empty()) {
        SipAck.SetContactHost(SipResponse.GetVecContact().begin()->GetUri().GetHost());
        SipAck.SetContactPort(SipResponse.GetVecContact().begin()->GetUri().GetPort());
    }
    SipAck.AddOtherHeaders(SipRequest.GetOtherHeaders());
    if (!ExtenHeader.empty()) {
        SipAck.AddOtherHeaders(ExtenHeader);
    }
    if (!ContentBody.empty()) {
        SipAck.SetContentType(MkSipContentSdp);
        SipAck.SetContentBody(ContentBody);
    }

    return SendSipMessage(SipAck);
}

Uint32 CMkSipServer::SendSipResponse(const CMkSipMessage& SipRequest, const MkSipStatus& StatusCode, const MkMapString& OtherHeader/* = MkMapString()*/, const MkSipContentType& ContentType/* = MkSipContentNone*/, const MkString& ContentBody /*= ""*/)
{
    Uint32 ErrorCode = NoneError;
    CMkSipMessage SipResponse;
    MkString ContactHost = SipRequest.GetRemoteHost();
    Uint16 ContactPort = SipRequest.GetRemotePort();
    if (!SipRequest.GetVecContact().empty()) {
        SipResponse.SetContactHost(SipRequest.GetVecContact().begin()->GetUri().GetHost());
        SipResponse.SetContactPort(SipRequest.GetVecContact().begin()->GetUri().GetPort());
    }
    BOOL bNat = !CMkUtil::IsLanIp(SipRequest.GetRemoteHost());
    SipResponse.SetRequestFlag(FALSE);
    SipResponse.SetStatusCode(StatusCode);
    SipResponse.SetFrom(SipRequest.GetFrom());
    SipResponse.SetRemoteHost(SipRequest.GetRemoteHost());
    SipResponse.SetRemotePort(SipRequest.GetRemotePort());
    SipResponse.SetTcpFlag(SipRequest.IsTcp());
    if (!SipRequest.GetVecVia().empty()) {
        MkList<CMkSipVia> VecVia = SipRequest.GetVecVia();
        CMkSipVia Via = VecVia.front();
        VecVia.pop_front();
        MkString strRPort;
        ErrorCode = Via.GetParamValue("rport", strRPort);
        if (NoneError == ErrorCode) {
            Via.UpdateParam("rport", std::to_string(SipRequest.GetRemotePort()));
            Via.UpdateParam("received", SipRequest.GetRemoteHost());
        }
        VecVia.push_front(Via);   //mast push front
        SipResponse.SetVecVia(VecVia);
    }

    CMkSipTo To = SipRequest.GetTo();
    if (MkSipStatusUnauthorized != StatusCode) {
        MkString strToTag;
        ErrorCode = To.GetParamValue("tag", strToTag);
        if (NoneError != ErrorCode) {
            CMkUtil::CreateRandomString(Len16, strToTag);
            To.UpdateParam("tag", strToTag);
        }
    }
    MkMapString::const_iterator it = OtherHeader.find("Contact");
    //only invite 200ok has contact header
    if (MkSipMethodInvite == SipRequest.GetMethod()
        && it == OtherHeader.end()) {
        CMkSipUri ContactUri;
        CMkSipContact Contact;
        ContactUri.SetUserName(m_SipId);
        if (SipRequest.IsTcp()) {
            if (bNat) {
                ContactUri.SetHost(m_pTcpListener->GetPublicHost());
                ContactUri.SetPort(m_pTcpListener->GetPublicPort());
            } else {
                ContactUri.SetHost(m_pTcpListener->GetListenHost());
                ContactUri.SetPort(m_pTcpListener->GetListenPort());
            }
        } else {
            if (bNat) {
                ContactUri.SetHost(m_pUdpListener->GetPublicHost());
                ContactUri.SetPort(m_pUdpListener->GetPublicPort());
            } else {
                ContactUri.SetHost(m_pUdpListener->GetListenHost());
                ContactUri.SetPort(m_pUdpListener->GetListenPort());
            }
        }
        Contact.SetUri(ContactUri);
        SipResponse.AddContact(Contact);
    }
    SipResponse.SetTo(To);
    SipResponse.SetCallId(SipRequest.GetCallId());
    SipResponse.SetCSeq(SipRequest.GetCSeq());
    SipResponse.AddOtherHeaders(OtherHeader);

    SipResponse.SetContentBody(ContentBody);
    CMkSipContentType TypeContent;
    switch (ContentType) {
    case MkSipContentXml:
        TypeContent.SetType("Application");
        TypeContent.SetSubType("MANSCDP+xml");
        break;
    case MkSipContentSdp:
        TypeContent.SetType("application");
        TypeContent.SetSubType("sdp");
        break;
    case MkSipContentRtsp:
        TypeContent.SetType("application");
        TypeContent.SetSubType("rtsp");
        break;
        break;
    default:
        break;
    }
    SipResponse.SetContentType(TypeContent);

    if (MkSipStatusOK == StatusCode) {
        if (MkSipMethodSubscribe == SipRequest.GetMethod()) {
            MkString strExpires;
            MkMapString::const_iterator it = OtherHeader.find("Expires");
            if (it != OtherHeader.end()) {
                strExpires = it->second;
            }
            Uint32 uExpires = std::stoi(strExpires);
            MkString SubscribeId = SipRequest.GetDialogId();
            m_pTimer->DeleteDelayer(SubscribeId);
            if (0 != uExpires) {
                AddDialog(SipRequest, SipResponse, CMkSipMessage(), CMkSipDialog::MkSipDialogCallee);
                m_pTimer->AddDelayer([this, SubscribeId]() {
                    DeleteDialog(SubscribeId);
                }, uExpires * 1000, SubscribeId);
            } else {
                DeleteDialog(SubscribeId);
            }
        } else if (MkSipMethodBye == SipRequest.GetMethod()) {
            DeleteDialog(SipRequest.GetDialogId());
        }
    }
    AddSipMessageToTransaction(SipResponse);
    return SendSipMessage(SipResponse);
}

Uint32 CMkSipServer::SendRefreshSubscribe(const MkString& SubId)
{
    return SendDialogMessage(SubId, MkSipMethodSubscribe, nullptr);
}

Uint32 CMkSipServer::SendRefreshRegister(const MkString& RegId)
{
    CMkSipDialog Dialog;
    Uint32 ErrorCode = GetDialog(RegId, Dialog);
    MkCheckErrorLog(ErrorCode, "input invalid dialog id:%s\n", RegId.c_str());

    CMkSipMessage SipMessage = Dialog.GetRequest();
    SipMessage.SetSipUri(Dialog.GetRequest().GetUri());
    SipMessage.SetTo(Dialog.GetResponse().GetTo());
    SipMessage.ClearVia();
    SipMessage.SetCSeq(m_SipSeqNo++);

    return SendSipMessage(SipMessage, [this](const CMkSipMessage& SipMessage) {
        AddSipMessageToTransaction(SipMessage);
    });
}

Uint32 CMkSipServer::OnSipBufferRecved(const Uint8* pBuf, Uint32 nLen, const MkString& RemoteHost, Uint16 RemotePort, const MkString& LocalHost, Uint16 LocalPort, BOOL bTcp, Uint32& nUsed)
{
    Uint32 ErrorCode = NoneError;
    nUsed = 0;
    while (nUsed < nLen) {
        CMkSipMessage SipMessage;
        SipMessage.SetRemoteHost(RemoteHost);
        SipMessage.SetRemotePort(RemotePort);
        SipMessage.SetLocalHost(LocalHost);
        SipMessage.SetLocalPort(LocalPort);
        SipMessage.SetTcpFlag(bTcp);
        Uint32 CurUsed = 0;
        ErrorCode = SipMessage.ParseContent(pBuf + nUsed, nLen - nUsed, CurUsed);
        if (NoneError != ErrorCode) {
            break;
        }
        if (!SipMessage.IsEmpty()) {
            if (CMkSipUtil::GetInstance().DebugMessageContent()) {
                MkString strBuf((const Int8*)pBuf + nUsed, CurUsed);
                MkDebugLog("recv sip message:\n%s\n", strBuf.c_str());
            }
            OnRecvSipMessage(SipMessage);
        }
        nUsed += CurUsed;
    }
    return ErrorCode;
}

Uint32 CMkSipServer::OnRecvSipMessage(const CMkSipMessage& SipMessage)
{
    //sip message master has via
    if (SipMessage.GetVecVia().empty()) {
        return InvalidParams;
    }
    Uint32 ErrorCode = NoneError;
    CMkSipTransaction TransAction;
    ErrorCode = UpdateTransaction(SipMessage, TransAction);
    MkCheckErrorLog(ErrorCode, "update transaction failed\n");
    if (SipMessage.IsRequest()) {
        if (MkSipMethodAck == SipMessage.GetMethod()) {
            if (MkSipStatusOK == TransAction.GetLastResponse().GetStatusCode()) {
                AddDialog(TransAction.GetRequest(), TransAction.GetLastResponse(), SipMessage, CMkSipDialog::MkSipDialogCallee);
            }
            OnSipRequest(MkSipRequestAck, SipMessage, nullptr);
        } else {
            //don't callback to the same transaction
            ErrorCode = OnRecvSipRequest(SipMessage);
        }
    } else {
        //status more than 200 is end response status
        if (MkSipStatusOK <= SipMessage.GetStatusCode()) {
            ErrorCode = OnRecvSipResponse(TransAction);
        }
    }
    return ErrorCode;
}

Uint32 CMkSipServer::OnRecvSipRequest(const CMkSipMessage& SipMessage)
{
    Uint32 ErrorCode = NoneError;
    MkSipRequestEvent RequestEvent = MkSipRequestEnd;
    CMkSipDialog Dialog;
    BOOL bDialog = NoneError == GetDialog(SipMessage.GetDialogId(), Dialog);
    if (MkSipMethodAck != SipMessage.GetMethod()) {
        AddSipMessageToTransaction(SipMessage, TRUE);
    }
    MkString strValue;
    switch (SipMessage.GetMethod()) {
    case MkSipMethodRegister:
        RequestEvent = MkSipRequestRegister;
        break;
    case MkSipMethodInvite:
        RequestEvent = MkSipRequestInvite;
        //send trying
        SendSipResponse(SipMessage, MkSipStatusTrying);
        break;
    case MkSipMethodAck:
        break;
    case MkSipMethodBye:
        if (!bDialog) {
            SendSipResponse(SipMessage, MkSipStatusCallDoesNotExist);
            return NoneError;
        } else {
            RequestEvent = MkSipRequestBye;
        }
        break;
    case MkSipMethodMessage:
        RequestEvent = bDialog ? MkSipRequestInviteMessage : MkSipRequestMessage;
        break;
    case MkSipMethodInfo:
        RequestEvent = bDialog ? MkSipRequestInviteInfo : MkSipRequestInfo;
        break;
    case MkSipMethodSubscribe:
        RequestEvent = MkSipRequestSubscribe;
        {
            MkMapString::const_iterator itExpires = SipMessage.GetOtherHeaders().find("Expires");
            MkMapString::const_iterator itEvent = SipMessage.GetOtherHeaders().find("Event");
            if (itExpires == SipMessage.GetOtherHeaders().end()
                || itEvent == SipMessage.GetOtherHeaders().end()) {
                SendSipResponse(SipMessage, MkSipStatusBadRequest);
                return NoneError;
            }
        }
        break;
    case MkSipMethodNotify:
        ErrorCode = SipMessage.GetHeaderValue("Event", strValue);
        if (NoneError == ErrorCode) {
            if (bDialog && CMkSipDialog::MkSipDialogSubscribe == Dialog.GetDialogType()) {
                RequestEvent = MkSipRequestSubscribeNotify;
            } else {
                SendSipResponse(SipMessage, MkSipStatusCallDoesNotExist);
                return NoneError;
            }
        } else {
            RequestEvent = MkSipRequestNotify;
        }
        break;
    default:
        break;
    }

    MkString TransId = SipMessage.GetTransactionId();
    ErrorCode = OnSipRequest(RequestEvent, SipMessage, [this, SipMessage](const MkSipStatus& Status, const MkMapString& ExternHeaders, const MkSipContentType& ContentType, const MkString& ResBody) {
        SendSipResponse(SipMessage, Status, ExternHeaders, ContentType, ResBody);
    });
    if (NoneError != ErrorCode) {
        SendSipResponse(SipMessage, MkSipStatusBadRequest);
    }
    return NoneError;
}

Uint32 CMkSipServer::OnRecvSipResponse(const CMkSipTransaction& Transaction)
{
    MkString DialogId = Transaction.GetRequest().GetDialogId();
    CMkSipDialog Dialog;
    BOOL bDialog = NoneError == GetDialog(DialogId, Dialog);
    MkSipResponseEvent ResponseEvent = MkSipResponseEnd;
    switch (Transaction.GetRequest().GetMethod()) {
    case MkSipMethodMessage:
        ResponseEvent = bDialog ? MkSipResponseInviteMessage : MkSipResponseMessage;
        break;
    case MkSipMethodInvite:
        //MkDebugLog("recv invite response\n");
        ResponseEvent = MkSipResponseInvite;
        break;
    case MkSipMethodInfo:
        ResponseEvent = bDialog ? MkSipResponseInviteInfo : MkSipResponseInfo;
        break;
    case MkSipMethodBye:
        ResponseEvent = MkSipResponseBye;
        break;
    case MkSipMethodSubscribe:
        ResponseEvent = MkSipResponseSubscribe;
        if (MkSipStatusOK == Transaction.GetLastResponse().GetStatusCode()) {
            MkString strExpries = "0";
            Transaction.GetLastResponse().GetHeaderValue("Expires", strExpries);
            Uint32 uExpires = std::stoi(strExpries);

            //subscribe success
            MkString SubscribeId = Transaction.GetRequest().GetDialogId();
            m_pTimer->DeleteDelayer(SubscribeId); //delete delayer first
            if (0 != uExpires) {
                AddDialog(Transaction.GetRequest(), Transaction.GetLastResponse(), CMkSipMessage(), CMkSipDialog::MkSipDialogCaller);
                m_pTimer->AddDelayer([this, SubscribeId]() {
                    SendRefreshSubscribe(SubscribeId);
                }, (uExpires - 10) * 1000, SubscribeId);
            } else {
                DeleteDialog(SubscribeId);
            }
        }
        break;
    case MkSipMethodNotify:
        if (MkSipStatusCallDoesNotExist == Transaction.GetLastResponse().GetStatusCode()
            || MkSipStatusRequestTimeout == Transaction.GetLastResponse().GetStatusCode()) {
            DeleteDialog(Transaction.GetRequest().GetDialogId());
            MkWarningLog("remote server not has this subscribe:%s\n", Transaction.GetRequest().GetDialogId().c_str());
        }
        ResponseEvent = bDialog ? MkSipResponseSubscribeNotify : MkSipResponseNotify;
        break;
    case MkSipMethodRegister:
        ResponseEvent = MkSipResponseRegister;
        if (MkSipStatusOK == Transaction.GetLastResponse().GetStatusCode()) {
            MkString strExpries = "0";
            Transaction.GetLastResponse().GetHeaderValue("Expires", strExpries);
            Uint32 uExpires = std::stoi(strExpries);

            //subscribe success
            MkString RegisterId = Transaction.GetRequest().GetDialogId();
            m_pTimer->DeleteDelayer(RegisterId); //delete delayer first
            if (0 != uExpires) {
                AddDialog(Transaction.GetRequest(), Transaction.GetLastResponse(), CMkSipMessage(), CMkSipDialog::MkSipDialogCaller);
                m_pTimer->AddDelayer([this, RegisterId]() {
                    SendRefreshRegister(RegisterId);
                }, (uExpires - 10) * 1000, RegisterId);
            } else {
                DeleteDialog(RegisterId);
            }
        } else {
            AddDialog(Transaction.GetRequest(), Transaction.GetLastResponse(), CMkSipMessage(), CMkSipDialog::MkSipDialogCaller);
        }
        break;
    default:
        break;
    }
    if (MkSipResponseEnd != ResponseEvent) {
        if (MkSipMethodInvite == Transaction.GetRequest().GetMethod()) {
            Uint32 ErrorCode = OnSipResponse(ResponseEvent, Transaction.GetRequest().GetTransactionId(), Transaction.GetRequest(), Transaction.GetLastResponse(), [this, Transaction](const MkMapString& ExternHeaders, const MkString& ResBody) {
                CMkSipMessage SipAck;
                if (MkSipStatusRequestTimeout != Transaction.GetLastResponse().GetStatusCode()) {
                    SendAck(Transaction.GetRequest(), Transaction.GetLastResponse(), ExternHeaders, ResBody, SipAck);
                }
                if (MkSipStatusOK == Transaction.GetLastResponse().GetStatusCode()) {
                    AddDialog(Transaction.GetRequest(), Transaction.GetLastResponse(), SipAck, CMkSipDialog::MkSipDialogCaller);
                }
            });
            if (NoneError != ErrorCode) {
                CMkSipMessage SipAck;
                SendAck(Transaction.GetRequest(), Transaction.GetLastResponse(), MkMapString(), "", SipAck);
            }
        } else {
            OnSipResponse(ResponseEvent, Transaction.GetRequest().GetTransactionId(), Transaction.GetRequest(), Transaction.GetLastResponse(), nullptr);
        }
    }
    return NoneError;
}

Uint32 CMkSipServer::OnTransactionTimer()
{
    //re send request or response
    CMkSipMessage DefaultResponse;
    DefaultResponse.SetStatusCode(MkSipStatusRequestTimeout);
    CMkTime NowTime = NowMkTime;
    MkVector<CMkSipTransaction> DefaultResponseTransActions;
    MkVector<CMkSipTransaction> VecResend;
    m_TranactionLock.WLock();
    MkMap<MkString, CMkSipTransaction>::iterator it = m_MapTranaction.begin();
    while (it != m_MapTranaction.end()) {
        // not compelete
        if (it->second.GetCompleteTime().IsEmpty()) {
            Uint32 OffsetCreateSec = NowTime.OffsetSec(it->second.GetCreateTime());
            if (OffsetCreateSec > CMkSipUtil::GetInstance().GetTransactionCheckSec()) {
                VecResend.push_back(it->second);
            }
            if (OffsetCreateSec > (int)CMkSipUtil::GetInstance().GetTransactionTimeOutSec()) {
                it->second.SetLastResponse(DefaultResponse);
                DefaultResponseTransActions.push_back(it->second);
            }
        } else {
            if (NowTime.OffsetSec(it->second.GetCompleteTime()) > (int)CMkSipUtil::GetInstance().GetTransactionDeleteSec()) {
                it = m_MapTranaction.erase(it);
                continue;
            }
        }
        it++;
    }
    m_TranactionLock.WUnlock();
    MkVector<CMkSipTransaction>::iterator itVec = DefaultResponseTransActions.begin();
    for (; itVec != DefaultResponseTransActions.end(); itVec++) {
        //send default response
        MkDebugLog("transaction:%s time out set default response\n", itVec->GetRequest().GetTransactionId().c_str());
        OnRecvSipResponse(*itVec);
    }
    itVec = VecResend.begin();
    for (; itVec != VecResend.end(); itVec++) {
        MkDebugLog("transaction:%s resend\n", itVec->GetRequest().GetTransactionId().c_str());
        ResendTransaction(*itVec);
    }
    return NoneError;
}

Uint32 CMkSipServer::UpdateTransaction(const CMkSipMessage& SipMsg, CMkSipTransaction& Transaction)
{
    MkDebugLog("get transactionid:%s\n", SipMsg.GetTransactionId().c_str());
    Uint32 ErrorCode = NoneError;
    m_TranactionLock.WLock();
    MkMap<MkString, CMkSipTransaction>::iterator it = m_MapTranaction.find(SipMsg.GetTransactionId());
    if (it != m_MapTranaction.end()) {
        if (SipMsg.IsRequest()) {
            if (MkSipMethodAck == SipMsg.GetMethod()) {
                it->second.SetAck(SipMsg);
                Transaction = it->second;
                ErrorCode = NoneError;
            } else {
                ErrorCode = InvalidParams; //try to replace request
            }
        } else if (MkSipStatusOK == Transaction.GetLastResponse().GetStatusCode()
            && MkSipMethodInvite == Transaction.GetRequest().GetMethod()) {
            ErrorCode = InvalidParams;
        } else {
            it->second.SetLastResponse(SipMsg);
            Transaction = it->second;
            ErrorCode = NoneError;
        }
    } else {
        if (!SipMsg.IsRequest()) {
            ErrorCode = InvalidParams;
        } else {
            if ((MkSipMethodAck == SipMsg.GetMethod())) {
                it->second.SetAck(SipMsg);
            } else {
                Transaction.SetType(MkSipMethodInvite == SipMsg.GetMethod() ? CMkSipTransaction::InviteCallee : CMkSipTransaction::NotInviteCallee);
                Transaction.SetRequest(SipMsg);
                m_MapTranaction[SipMsg.GetTransactionId()] = Transaction;
            }
        }
    }
    m_TranactionLock.WUnlock();
    return ErrorCode;
}

Uint32 CMkSipServer::AddSipMessageToTransaction(const CMkSipMessage& SipMsg, BOOL bCallee/* = FALSE*/)
{
    Uint32 ErrorCode = InvalidParams;
    if (SipMsg.IsRequest()) {
        CMkSipTransaction TransAction;
        if (MkSipMethodAck != SipMsg.GetMethod()) {
            if (bCallee) {
                TransAction.SetType(MkSipMethodInvite == SipMsg.GetMethod() ? CMkSipTransaction::InviteCallee : CMkSipTransaction::NotInviteCallee);
            } else {
                TransAction.SetType(MkSipMethodInvite == SipMsg.GetMethod() ? CMkSipTransaction::InviteCaller : CMkSipTransaction::NotInviteCaller);
            }

            //MkInfoLog("add trans action:%s\n", SipMsg.GetTransactionId().c_str());
            TransAction.SetRequest(SipMsg);
            m_TranactionLock.WLock();
            m_MapTranaction[SipMsg.GetTransactionId()] = TransAction;
            m_TranactionLock.WUnlock();
            ErrorCode = NoneError;
        } else {
            m_TranactionLock.WLock();
            MkMap<MkString, CMkSipTransaction>::iterator it = m_MapTranaction.find(SipMsg.GetTransactionId());
            if (it != m_MapTranaction.end()) {
                it->second.SetAck(SipMsg);
                TransAction = it->second;
                ErrorCode = NoneError;
            }
            m_TranactionLock.WUnlock();
            AddDialog(TransAction.GetRequest(), TransAction.GetLastResponse(), SipMsg, CMkSipDialog::MkSipDialogCaller);
        }
    } else { //response
        m_TranactionLock.WLock();
        MkMap<MkString, CMkSipTransaction>::iterator it = m_MapTranaction.find(SipMsg.GetTransactionId());
        if (it != m_MapTranaction.end()) {
            it->second.SetLastResponse(SipMsg);
            ErrorCode = NoneError;
        }
        m_TranactionLock.WUnlock();
    }
    return ErrorCode;
}

Uint32 CMkSipServer::DeleteTransaction(const MkString& TransId)
{
    //MkDebugLog("delete transaction:%s\n", TransId.c_str());
    Uint32 ErrorCode = InvalidId;
    m_TranactionLock.WLock();
    MkMap<MkString, CMkSipTransaction>::iterator it = m_MapTranaction.find(TransId);
    if (it != m_MapTranaction.end()) {
        //MkDebugLog("delete transaction:%s  success\n", TransId.c_str());
        m_MapTranaction.erase(it);
    }
    m_TranactionLock.WUnlock();
    return ErrorCode;
}

Uint32 CMkSipServer::AddDialog(const CMkSipMessage& Request, const CMkSipMessage& Response, const CMkSipMessage& Ack, const CMkSipDialog::MkSipCallType& CallType)
{
    CMkSipDialog Dialog;
    Dialog.SetCallType(CallType);
    Dialog.SetRequest(Request);
    Dialog.SetResponse(Response);
    Dialog.SetAck(Ack);

    if (MkSipMethodInvite == Request.GetMethod()) {
        Dialog.SetDialogType(CMkSipDialog::MkSipDialogInvite);
    } else if (MkSipMethodRegister == Request.GetMethod()) {
        Dialog.SetDialogType(CMkSipDialog::MkSipDialogRegister);
    } else if (MkSipMethodSubscribe == Request.GetMethod()) {
        Dialog.SetDialogType(CMkSipDialog::MkSipDialogSubscribe);
    }

    MkInfoLog("add dialog:%s\n", Request.GetDialogId().c_str());
    m_DialogLock.WLock();
    m_MapDialog[Request.GetDialogId()] = Dialog;
    m_DialogLock.WUnlock();
    return NoneError;
}

Uint32 CMkSipServer::GetDialog(const MkString& DailogId, CMkSipDialog& Dailog)
{
    //MkInfoLog("find dialog:%s\n", DailogId.c_str());
    Uint32 ErrorCode = InvalidId;
    m_DialogLock.RLock();
    MkMap<MkString, CMkSipDialog>::iterator it = m_MapDialog.find(DailogId);
    if (it != m_MapDialog.end()) {
        Dailog = it->second;
        ErrorCode = NoneError;
    }
    m_DialogLock.RUnlock();
    return ErrorCode;
}

Uint32 CMkSipServer::DeleteDialog(const MkString& DailogId)
{
    MkInfoLog("delete dialog:%s\n", DailogId.c_str());
    Uint32 ErrorCode = InvalidId;
    m_DialogLock.RLock();
    MkMap<MkString, CMkSipDialog>::iterator it = m_MapDialog.find(DailogId);
    if (it != m_MapDialog.end()) {
        m_MapDialog.erase(it);
        ErrorCode = NoneError;
    }
    m_DialogLock.RUnlock();
    return ErrorCode;
}

Uint32 CMkSipServer::ResendTransaction(const CMkSipTransaction& Transaction)
{
    MkString strSip;
    Uint32 ErrorCode = NoneError;
    CMkSipMessage SendMsg;
    if (CMkSipTransaction::InviteCaller == Transaction.GetType()
        || CMkSipTransaction::NotInviteCaller == Transaction.GetType()) {
        SendMsg = Transaction.GetRequest();
        MkDebugLog("resend request transaction:%s\n", Transaction.GetLastResponse().GetTransactionId().c_str());
    } else if (MkSipMethodInvite == Transaction.GetRequest().GetMethod()) {
        SendMsg = Transaction.GetLastResponse();
    }
    if (!SendMsg.IsEmpty()) {
        SendSipMessage(SendMsg, nullptr, TRUE);
    }
    return NoneError;
}

Uint32 CMkSipServer::PacketVia(const CMkSipMessage& SipRequest, CMkSipVia& Via)
{
    /*Via.SetProtocol()
    const CMkSipListener *pListener = nullptr;
    if (CMkSocket::UdpSession == pSocket->SocketType()) {
        Via.SetProtocol("UDP");
        pListener = dynamic_cast<const CMkSipListener*>(pSocket);
    } else {
        Via.SetProtocol("TCP");
        CMkSipTcpSession *pSession = dynamic_cast<CMkSipTcpSession*>(pSocket);
        if (pSession) {
            pListener = dynamic_cast<const CMkSipListener*>(pSession->GetParentServer());
        }
    }
    if (pListener) {
        Via.SetHost(pListener->GetContactHost());
        Via.SetPort(pListener->GetContactPort());
    }
    Via.UpdateParam("rport", "");
    Via.SetBranch("z9hG4bK" + std::to_string(CMkUtil::GetRandomNumber()));*/
    return NoneError;
}

Uint32 CMkSipServer::SendSipMessage(const CMkSipMessage& SipMessage, const SipMsgCompleteCallback& Cb/* = nullptr*/, BOOL bResend/* = FALSE*/)
{
    Uint32 ErrorCode = NoneError;
    if (SipMessage.IsTcp()) {
        ErrorCode = m_pTcpListener->SendSipMessage(SipMessage, Cb, bResend);
    } else {
        ErrorCode = m_pUdpListener->SendSipMessage(SipMessage, Cb, bResend);
    }
    return ErrorCode;
}

CMkSipServer::~CMkSipServer()
{
    Stop();
}

